package cn.icanci.loopstack.rec.engine.sdk.extensions;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author icanci
 * @since 1.0 Created in 2022/11/15 21:15
 */
public class RecExtensionLoader<T> {

    private static final Logger logger            = LoggerFactory.getLogger(RecExtensionLoader.class);

    /**
     * 约定第三方实现配置文件目录
     **/
    private static final String SERVICE_DIRECTORY = "META-INF/rec/";

    /**
     * 接口的类型，用于获取此接口下的第三方实现
     **/
    private final Class<?>      type;

    private RecExtensionLoader(Class<?> type) {
        this.type = type;
    }

    /**
     * 通过接口的{@link Class}对象获取其第三方实现类的加载器
     *
     * @param type type
     * @param <T> <T>
     * @return ExtensionLoader<T> 返回一个指定接口类型的类加载器辅助类
     */
    public static <T> RecExtensionLoader<T> getExtensionLoader(Class<T> type) {
        if (type == null) {
            throw new IllegalArgumentException("SPI needs to know which third-party implementation you want to find");
        }
        if (!type.isInterface()) {
            throw new IllegalArgumentException("Only third-party implementations of interface types are supported!");
        }
        if (type.getAnnotation(RecSpi.class) == null) {
            throw new IllegalArgumentException("The target interface must be marked with @RecSpi annotation!");
        }
        return new RecExtensionLoader<>(type);
    }

    /**
     * 获取这个接口指定名称的第三方实现对象
     *
     * @return 返回目标实现
     */
    public T getExtension() {
        Class<T> clazz = loadExtensionFile();
        if (clazz == null) {
            return null;
        }
        try {
            return clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException("Instantiation failed: " + clazz);
        }
    }

    /**
     * 加载约定好的目录下方的名称为接口全路径的扩展文件
     *
     * @return Class<T> 返回目标第三方实现的{@link Class}对象
     */
    private Class<T> loadExtensionFile() {
        String fileName = RecExtensionLoader.SERVICE_DIRECTORY + type.getName();
        try {
            Enumeration<URL> urls;
            ClassLoader classLoader = RecExtensionLoader.class.getClassLoader();
            urls = classLoader.getResources(fileName);
            if (urls != null) {
                URL resourceUrl = urls.nextElement();
                return loadResource(classLoader, resourceUrl);
            }
            return null;
        } catch (IOException e) {
            logger.error("[RecExtensionLoader][loadExtensionFile] error:{}", e.getMessage());
            return null;
        }
    }

    /**
     * 读取扩展文件的内容，找到第三方实现的全路径，并获得其{@link Class}对象
     *
     * @param classLoader 扩展类加载器辅助类的类加载器
     * @param resourceUrl 文件在资源{@code URL}
     * @return Class<T> 返回目标{@link Class}对象
     */
    @SuppressWarnings("unchecked")
    private Class<T> loadResource(ClassLoader classLoader, URL resourceUrl) {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceUrl.openStream(), StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                final int ci = line.indexOf('#');
                if (ci == 0) {
                    continue;
                } else if (ci > 0) {
                    line = line.substring(0, ci);
                }
                return (Class<T>) classLoader.loadClass(line.trim());
            }
        } catch (IOException | ClassNotFoundException e) {
            logger.error("[RecExtensionLoader][loadResource] error:{}", e.getMessage());
            return null;
        }
        return null;
    }
}
